/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>

#include "parcel.h"

namespace OHOS {
namespace SeBaseServices {
namespace UnitTest {
using namespace testing;
TEST(ParcelTest, ParcelCreateAndDelete)
{
    Parcel parcel = CreateParcel(1024);
    EXPECT_EQ(parcel.beginPos, 0);
    EXPECT_EQ(parcel.endPos, 0);
    EXPECT_EQ(parcel.length, 1024);
    EXPECT_NE(parcel.data, nullptr);

    DeleteParcel(&parcel);
    EXPECT_EQ(parcel.beginPos, 0);
    EXPECT_EQ(parcel.endPos, 0);
    EXPECT_EQ(parcel.length, 0);
    EXPECT_EQ(parcel.data, nullptr);
}

TEST(ParcelTest, ParcelCreateAndWrite)
{
    Parcel parcel = CreateParcel(sizeof(uint32_t) + sizeof(uint32_t));

    EXPECT_TRUE(ParcelWriteUint32(&parcel, 1234));
    EXPECT_TRUE(ParcelWriteUint32(&parcel, 5678));
    EXPECT_FALSE(ParcelWriteUint32(&parcel, 0xabcd));

    uint32_t value = 0;

    EXPECT_TRUE(ParcelReadUint32(&parcel, &value));
    EXPECT_EQ(value, 1234);

    EXPECT_TRUE(ParcelReadUint32(&parcel, &value));
    EXPECT_EQ(value, 5678);

    EXPECT_FALSE(ParcelReadUint32(&parcel, &value));

    EXPECT_TRUE(ParcelWriteUint32(&parcel, 1111));
    EXPECT_TRUE(ParcelReadUint32(&parcel, &value));
    EXPECT_EQ(value, 1111);

    EXPECT_TRUE(ParcelWriteUint32(&parcel, 2222));
    EXPECT_TRUE(ParcelWriteUint32(&parcel, 3333));
    EXPECT_FALSE(ParcelWriteUint32(&parcel, 4444));

    EXPECT_TRUE(ParcelReadUint32(&parcel, &value));
    EXPECT_EQ(value, 2222);

    EXPECT_TRUE(ParcelReadUint32(&parcel, &value));
    EXPECT_EQ(value, 3333);

    DeleteParcel(&parcel);
    EXPECT_EQ(parcel.beginPos, 0);
    EXPECT_EQ(parcel.endPos, 0);
    EXPECT_EQ(parcel.length, 0);
    EXPECT_EQ(parcel.data, nullptr);
}

TEST(ParcelTest, ParcelGetDataAndDataSize)
{
    Parcel parcel = CreateParcel(1024);

    for (uint32_t i = 0; i < 100; i++) {
        EXPECT_TRUE(ParcelWriteUint32(&parcel, i));
    }

    EXPECT_EQ(100 * sizeof(uint32_t), GetParcelDataSize(&parcel));

    for (uint32_t i = 0; i < 50; i++) {
        uint32_t value = 0;
        EXPECT_TRUE(ParcelReadUint32(&parcel, &value));
        EXPECT_EQ(value, i);
    }

    EXPECT_EQ(50 * sizeof(uint32_t), GetParcelDataSize(&parcel));

    DeleteParcel(&parcel);
    EXPECT_EQ(parcel.beginPos, 0);
    EXPECT_EQ(parcel.endPos, 0);
    EXPECT_EQ(parcel.length, 0);
    EXPECT_EQ(parcel.data, nullptr);
}

TEST(ParcelTest, InstantParceForRead)
{
    uint8_t data[] = {0x12, 0x34, 0x88, 0x88, 0x47, 0x90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0x90, 0x00};
    Parcel parcel = CreateParcelWithData(data, sizeof(data));
    EXPECT_EQ(parcel.beginPos, 0);

    uint16_t version = 0;
    EXPECT_TRUE(ParcelReadUint16(&parcel, &version));
    EXPECT_EQ(version, 0x3412);

    uint32_t vendor = 0;
    EXPECT_TRUE(ParcelReadUint32(&parcel, &vendor));
    EXPECT_EQ(vendor, 0x90478888);

    uint8_t config[12] = {0};
    EXPECT_TRUE(ParcelRead(&parcel, config, 12));
    EXPECT_EQ(config[0], 1);
    EXPECT_EQ(config[1], 2);
    EXPECT_EQ(config[2], 3);
    EXPECT_EQ(config[3], 4);
    EXPECT_EQ(config[4], 5);
    EXPECT_EQ(config[5], 6);
    EXPECT_EQ(config[6], 7);
    EXPECT_EQ(config[7], 8);
    EXPECT_EQ(config[8], 9);
    EXPECT_EQ(config[9], 10);
    EXPECT_EQ(config[10], 11);
    EXPECT_EQ(config[11], 12);

    uint16_t result = 0;
    EXPECT_TRUE(ParcelReadUint16(&parcel, &result));
    EXPECT_EQ(result, 0x90);

    EXPECT_EQ(parcel.beginPos, sizeof(data));

    DeleteParcel(&parcel);
}

TEST(ParcelTest, ParcelToDataBuffer)
{
    Parcel parcel = CreateParcel(1024);

    for (uint32_t i = 0; i < 100; i++) {
        EXPECT_TRUE(ParcelWriteUint32(&parcel, i));
    }

    EXPECT_EQ(100 * sizeof(uint32_t), GetParcelDataSize(&parcel));

    for (uint32_t i = 0; i < 50; i++) {
        uint32_t value = 0;
        EXPECT_TRUE(ParcelReadUint32(&parcel, &value));
        EXPECT_EQ(value, i);
    }
    {
        uint8_t buffer[200] = {0};
        uint32_t size = 199;
        EXPECT_FALSE(ParcelToDataBuffer(&parcel, buffer, &size));
    }

    {
        uint8_t buffer[200] = {0};
        uint32_t size = 200;
        EXPECT_TRUE(ParcelToDataBuffer(&parcel, buffer, &size));
        for (uint32_t loop = 0; loop < 50; loop++) {
            auto curr = *((uint32_t *)buffer + loop);
            EXPECT_EQ(curr, loop + 50);
        }
    }

    DeleteParcel(&parcel);
}

TEST(ParcelTest, DeleteParcelWillNotCrash)
{
    // will not crash
    DeleteParcel(nullptr);
}

TEST(ParcelTest, ParcelRead)
{
    uint8_t data[] = {0x12, 0x34, 0x88, 0x88, 0x47, 0x90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0x90, 0x00};
    Parcel parcel = CreateParcelWithData(data, sizeof(data));

    {
        EXPECT_FALSE(ParcelRead(nullptr, nullptr, 0));
    }
    {
        EXPECT_FALSE(ParcelRead(&parcel, nullptr, 0));
    }
    {
        uint8_t dest[8] = {0};
        EXPECT_FALSE(ParcelRead(&parcel, dest, 0));
    }
    {
        uint8_t dest[8] = {0};
        EXPECT_TRUE(ParcelRead(&parcel, dest, sizeof(dest)));
    }
    {
        uint8_t dest[8] = {0};
        EXPECT_FALSE(ParcelRead(&parcel, dest, UINT32_MAX - 1));
    }
    {
        uint8_t dest[128] = {0};
        EXPECT_FALSE(ParcelRead(&parcel, dest, sizeof(dest)));
    }

    DeleteParcel(&parcel);
}

TEST(ParcelTest, ParcelWrite)
{
    Parcel parcel = CreateParcel(1024);

    {
        auto ret = ParcelWrite(nullptr, nullptr, 0);
        EXPECT_FALSE(ret);
    }

    {
        auto ret = ParcelWrite(&parcel, nullptr, 0);
        EXPECT_FALSE(ret);
    }

    {
        uint8_t data[32] = {0};
        auto ret = ParcelWrite(&parcel, data, 0);
        EXPECT_FALSE(ret);
    }
    {
        uint8_t data[32] = {0};
        auto ret = ParcelWrite(&parcel, data, sizeof(data));
        EXPECT_TRUE(ret);
    }
    {
        uint8_t data[32] = {0};
        auto ret = ParcelWrite(&parcel, data, UINT32_MAX - 1);
        EXPECT_FALSE(ret);
    }

    DeleteParcel(&parcel);
}
} // namespace UnitTest
} // namespace SeBaseServices
} // namespace OHOS